from typing import Annotated, List, Optional

from fastapi import APIRouter, Body, Depends, Path, Query, Request

from app.api.deps import CurrentUserDep, DictServiceDep, require_permission
from app.core import settings
from app.enums.log_module import LogModuleEnum
from app.exceptions.base import AppException
from app.models.system import SysUser
from app.schemas.base import Pagination, Response
from app.schemas.dict import DictForm, DictItemForm, DictItemPageVO, DictPageVO
from app.schemas.option import StringOption
from app.utils.log_api_call import log

router = APIRouter(prefix=f"{settings.API_V1_STR}/dicts", tags=["06.字典接口"])


# ========================
# 字典相关接口
# ========================


@router.get(
    "/page", response_model=Response[Pagination[DictPageVO]], summary="字典分页列表", description="分页查询字典列表"
)
@log(content="字典分页列表", module=LogModuleEnum.DICT.label)
async def get_dict_page(
    request: Request,
    current_user: CurrentUserDep,
    dict_service: DictServiceDep,
    page_num: Optional[int] = Query(default=1, min=1, alias="pageNum", description="页码"),
    page_size: Optional[int] = Query(default=10, min=10, max=1000, alias="pageSize", description="每页记录数"),
    keywords: Optional[str] = Query(default=None, description="关键字(字典名称)", alias="keywords"),
) -> Response[Pagination[DictPageVO]]:
    """
    字典分页列表
    """
    try:
        reulst = await dict_service.get_dict_page(page_num=page_num, page_size=page_size, keywords=keywords)
        return Response.success(data=reulst)
    except Exception as e:
        raise AppException(message="获取字典分页列表失败") from e


@router.get(
    "", response_model=Response[List[StringOption]], summary="字典列表", description="获取所有字典的下拉选项列表"
)
async def get_dict_list(current_user: CurrentUserDep, dict_service: DictServiceDep) -> Response[List[StringOption]]:
    """
    字典列表
    """
    try:
        result = await dict_service.get_dict_list()
        rs = [StringOption(label=dict_.name, value=dict_.dict_code) for dict_ in result]
        return Response.success(data=rs)
    except Exception as e:
        raise AppException(message="获取字典列表失败") from e


@router.get(
    "/{id}/form",
    response_model=Response[DictForm],
    summary="获取字典表单数据",
    description="根据字典ID获取编辑表单数据",
)
async def get_dict_form(
    dict_service: DictServiceDep,
    id: Annotated[int, Path(..., description="字典ID")],
    current_user: CurrentUserDep,
) -> Response[DictForm]:
    """
    获取字典表单数据
    """
    try:
        dict_ = await dict_service.get_dict_by_id(id)
        if not dict_:
            raise AppException(message="字典不存在")
        data = DictForm.model_validate(dict_)
        return Response.success(data=data)
    except Exception as e:
        raise AppException(message="获取字典表单数据失败") from e


@router.post("", response_model=Response[None], summary="新增字典", description="创建新字典，需 sys:dict:add 权限")
@log(content="新增字典", module=LogModuleEnum.DICT.label)
async def save_dict(
    request: Request,
    dict_service: DictServiceDep,
    current_user: Annotated[SysUser, Depends(require_permission("sys:dict:add"))],
    form_data: Annotated[DictForm, Body(..., description="字典表单数据")],
) -> Response[None]:
    """
    新增字典
    """
    try:
        await dict_service.save_dict(form_data)
        return Response.success(data=None)
    except Exception as e:
        raise AppException(message="新增字典失败") from e


@router.put(
    "/{id}", response_model=Response[None], summary="修改字典", description="更新字典信息，需 sys:dict:edit 权限"
)
@log(content="修改字典", module=LogModuleEnum.DICT.label)
async def update_dict(
    request: Request,
    dict_service: DictServiceDep,
    current_user: Annotated[SysUser, Depends(require_permission("sys:dict:edit"))],
    id: Annotated[int, Path(..., description="字典ID")],
    dict_form: Annotated[DictForm, Body(..., description="字典表单数据")],
) -> Response[None]:
    """
    修改字典
    """
    try:
        dict_form.id = id
        await dict_service.update_dict(dict_form)
        return Response.success(data=None)
    except Exception as e:
        raise AppException(message="修改字典失败") from e


@router.delete(
    "/{ids}",
    response_model=Response[None],
    summary="删除字典",
    description="批量删除字典，多个ID用英文逗号分隔，需 sys:dict:delete 权限",
)
@log(content="删除字典", module=LogModuleEnum.DICT.label)
async def delete_dictionaries(
    request: Request,
    dict_service: DictServiceDep,
    current_user: Annotated[SysUser, Depends(require_permission("sys:dict:delete"))],
    ids: Annotated[str, Path(..., description="字典ID，多个以英文逗号(,)拼接")],
) -> Response[None]:
    """
    删除字典
    """
    try:
        id_list = [int(id) for id in ids.split(",")]
        await dict_service.delete_dict_by_ids(id_list)
        return Response.success(data=None)
    except Exception as e:
        raise AppException(message="删除字典失败") from e


# ========================
# 字典项相关接口
# ========================


@router.get(
    "/{dictCode}/items/page",
    response_model=Response[Pagination[DictItemPageVO]],
    summary="字典项分页列表",
    description="分页查询指定字典编码下的字典项",
)
async def get_dict_item_page(
    current_user: CurrentUserDep,
    dict_service: DictServiceDep,
    dictCode: str = Path(..., description="字典编码"),
    page_num: int = Query(default=1, min=1, alias="pageNum", description="页码"),
    page_size: int = Query(default=10, min=10, max=1000, alias="pageSize", description="每页记录数"),
    keywords: Optional[str] = Query(default=None, description="关键字(字典项值/字典项名称)", alias="keywords"),
) -> Response[Pagination[DictItemPageVO]]:
    """
    字典项分页列表
    """
    try:
        result = await dict_service.get_dict_item_page(
            page_num=page_num,
            page_size=page_size,
            keywords=keywords,
            dict_code=dictCode,
        )
        return Response.success(data=result)
    except Exception as e:
        raise AppException(message="获取字典项分页列表失败") from e


@router.get(
    "/{dictCode}/items/{itemId}/form",
    response_model=Response[DictItemForm],
    summary="字典项表单数据",
    description="根据字典项ID获取编辑表单数据",
)
async def get_dict_item_form(
    current_user: CurrentUserDep,
    dict_service: DictServiceDep,
    dictCode: Annotated[str, Path(..., description="字典编码")],
    itemId: Annotated[int, Path(..., description="字典项ID")],
) -> Response[DictItemForm]:
    """
    字典项表单数据
    """
    try:
        result = await dict_service.get_dict_item_by_id(itemId)
        if not result:
            return Response.success(data=DictItemForm())
        return Response.success(data=DictItemForm.model_validate(result))
    except Exception as e:
        raise AppException(message="获取字典项表单数据失败") from e


@router.get(
    "/{dictCode}/items",
    response_model=Response[List[StringOption]],
    summary="字典项列表",
    description="获取指定字典编码下的所有字典项",
)
async def get_dict_items(
    current_user: CurrentUserDep,
    dict_service: DictServiceDep,
    dictCode: str = Path(..., description="字典编码"),
) -> Response[List[StringOption]]:
    """
    字典项列表
    """
    try:
        result = await dict_service.get_dict_item_list(dict_code=dictCode)
        if not result:
            return Response.success(data=[])
        rs = [StringOption(label=item.label, value=item.value, tag=item.tag_type) for item in result]
        return Response.success(data=rs)
    except Exception as e:
        raise AppException(message="获取字典项列表失败") from e


@router.post(
    "/{dictCode}/items",
    response_model=Response[None],
    summary="新增字典项",
    description="为指定字典新增字典项，需 sys:dict-item:add 权限",
)
@log(content="新增字典项", module=LogModuleEnum.DICT.label)
async def save_dict_item(
    request: Request,
    current_user: Annotated[SysUser, Depends(require_permission("sys:dict-item:add"))],
    dict_service: DictServiceDep,
    dictCode: Annotated[str, Path(..., description="字典编码")],
    form_data: Annotated[DictItemForm, Body(..., description="字典项表单数据")],
) -> Response[None]:
    """
    新增字典项
    """
    try:
        form_data.dict_code = dictCode
        await dict_service.save_dict_item(form_data)
        return Response.success(data=None)
    except Exception as e:
        raise AppException(message="新增字典项失败") from e


@router.put(
    "/{dictCode}/items/{itemId}",
    response_model=Response[None],
    summary="修改字典项",
    description="更新字典项信息，需 sys:dict-item:edit 权限",
)
@log(content="修改字典项", module=LogModuleEnum.DICT.label)
async def update_dict_item(
    request: Request,
    dict_service: DictServiceDep,
    current_user: Annotated[SysUser, Depends(require_permission("sys:dict-item:edit"))],
    dictCode: Annotated[str, Path(..., description="字典编码")],
    itemId: Annotated[int, Path(..., description="字典项ID")],
    form_data: Annotated[DictItemForm, Body(..., description="字典项表单数据")],
) -> Response[None]:
    """
    修改字典项
    """
    try:
        form_data.id = itemId
        form_data.dict_code = dictCode
        await dict_service.update_dict_item(form_data)
        return Response.success(data=None)
    except Exception as e:
        raise AppException(message="修改字典项失败") from e


@router.delete(
    "/{dictCode}/items/{itemIds}",
    response_model=Response[None],
    summary="删除字典项",
    description="批量删除字典项，多个ID用英文逗号分隔，需 sys:dict-item:delete 权限",
)
@log(content="删除字典项", module=LogModuleEnum.DICT.label)
async def delete_dict_items(
    request: Request,
    dict_service: DictServiceDep,
    current_user: Annotated[SysUser, Depends(require_permission("sys:dict-item:delete"))],
    dictCode: Annotated[str, Path(..., description="字典编码")],
    itemIds: Annotated[str, Path(..., description="字典ID，多个以英文逗号(,)拼接")],
) -> Response[None]:
    """
    删除字典项
    """
    try:
        id_list = [int(id) for id in itemIds.split(",")]
        await dict_service.delete_dict_item_by_ids(id_list)
        return Response.success(data=None)
    except Exception as e:
        raise AppException(message="删除字典项失败") from e
